/** \file    bitmap.cpp
  * \brief   Binary raster
  * \date    2001 - 2003
  * \author  Pavel Agapov
  * \author  Fedor Chelnokov
  * \version $Header: /home/cscom1r4/cvsroot/cs/imglib/src/bitmap.cpp,v 1.1 2004/02/04 14:43:23 cscom1r4 Exp $
  */

#include "imglib/bitmap.h"
#include <memory.h>
#include <algorithm>

namespace img {

void bitmap::update_scans() {
	_scans.resize(_height);
	unsigned int n = 0;
	if (_order == bottom_up) {
		std::vector<byte *>::reverse_iterator it;
		for (it = _scans.rbegin(); it != _scans.rend(); ++it)
			* it = _data + (n++) * _scansize;
	} else {
		std::vector<byte *>::iterator it;
		for (it = _scans.begin(); it != _scans.end(); ++it)
			* it = _data + (n++) * _scansize;
	}
}
	
void bitmap::recalc(size_type w, size_type h, size_type a) {
	_width = w;
	_height = h;
	_alignment = a;
	_scansize = _width / 8 + ((_width % 8) != 0 ? 1 : 0);
	if (_alignment > 1)
		if ((_scansize % _alignment) != 0)
			_scansize = (_scansize / _alignment + 1) * _alignment;
	_bytes = _scansize * _height;
}

void bitmap::resize(size_type w, size_type h, size_type a)
{
	if (a == 0)
		a = _alignment;
	if (!_owner || w != _width || h != _height || a != _alignment) {
		size_type old_bytes = _bytes;	
		std::vector<byte *> old_scans(_scans);
		byte * old_data = _data;
		bool copy_data = (_data != 0 && w == _width && h == _height);
		recalc(w, h, a);
		if (_bytes != old_bytes)
			_data = _bytes != 0 ? new byte[_bytes] : 0;
		update_scans();
		if (copy_data)
			for (unsigned int n = 0; n < _scans.size(); ++n)
				memcpy(_scans[n], old_scans[n], _width / 8 + ((_width % 8) != 0 ? 1 : 0));
		if (_owner && old_data != 0 && old_data != _data)
			delete [] old_data;
		_owner = true;
	}
}

void bitmap::attach(void * data, size_type w, size_type h, size_type a) {
	if (a == 0)
		a = _alignment;
	if (_owner)
		resize(0, 0);
	if (data != _data || w != _width || h != _height || a != _alignment) {
		recalc(w, h, a);
		_data = reinterpret_cast<byte *>(data);
		update_scans();
		_owner = false;
	}
}

void * bitmap::detach() {
	void * data = _data;
	recalc(0, 0, 0);
	_data = 0;
	_scans.clear();
	return data;
}

void bitmap::flip() {
	size_type src, dest, count = _width / 8 + ((_width % 8) != 0 ? 1 : 0);
	for (src = 0, dest = _height - 1; src < dest; ++src, --dest) {
		//see comments in the same function of image
		std::swap_ranges(_scans[src], _scans[src] + count, _scans[dest]);
	}
}

void bitmap::fill(bool value) {
	if (_data != 0)
		memset(_data, value ? 0xFFFFFFFF : 0, _bytes);
}

void bitmap::swap(bitmap & b) {
	if (this == &b) 
		return;
	std::swap(_data, b._data);
	std::swap(_owner, b._owner);
	std::swap(_width, b._width);
	std::swap(_height, b._height);
	std::swap(_alignment, b._alignment);
	std::swap(_order, b._order);
	std::swap(_scansize, b._scansize);
	std::swap(_bytes, b._bytes);
	_scans.swap(b._scans );
}

inline int set_bit_count( unsigned char b ) {
	return ( b  & 0x00000001) + 
		((b>>1) & 0x00000001) +
		((b>>2) & 0x00000001) +
		((b>>3) & 0x00000001) +
		((b>>4) & 0x00000001) +
		((b>>5) & 0x00000001) +
		((b>>6) & 0x00000001) +
		((b>>7) & 0x00000001);
}

int bitmap::set_bit_count() const {
	int count = 0;
	int fullscan = _width / 8;
	int remlast = _width % 8;
	std::vector<byte *>::const_iterator s;
	for( s = _scans.begin(); s != _scans.end(); ++s ) {
		const byte *d = *s;
		for( int i = 0; i < fullscan; ++i, ++d ) {
			count += img::set_bit_count( *d );
		}
		count += img::set_bit_count( *d & (0xFF << (8 - remlast)) );
	}
	return count;
}

void bitmap::inverse() {
	byte *p = _data;
	size_type r = _bytes;
	while (r--)
		*p++ ^= 0xff;
}

} // img
